<!--炼焦循环图-->
<template>
    <div class="d3-chart" :id="domId" :style="{ width: width, height: height }"></div>
</template>

<script>
import * as d3 from "d3";

export default {
  name: "d3-chart",
  data() {
    return {
      domId: "d3-chart-" + +new Date()
    };
  },
  props: {
    d3ChartData: {
      required: true,
      type: Object,
      default: () => {}
    },
    scale: {
      type: Number,
      default: 1
    },
    height: {
      type: String,
      default: "500px"
    },
    width: {
      type: String,
      default: "100%"
    }
  },

  watch: {
    d3ChartData: function() {
      this.renderChart();
    },
    scale() {
      this.renderChart();
      event.preventDefault();
    }
  },
  methods: {
    transformData: function(lineData) {
      return lineData.map(function(l) {
        return [`M${l.xFrom} ${l.yFrom} L${l.xTo} ${l.yTo}`];
      });
    },
    renderChart: function() {
      const vm = this;
      let {
        lineData = [],
        circleData = [],
        circleLineData = []
      } = vm.d3ChartData;
      if (!lineData.length) return;

      const domId = "#" + this.domId;

      //移除所有元素
      d3.selectAll(domId + " svg").remove();
      const svg = d3.select(domId).append("svg");

      lineData = this.transformData(lineData);
      let viewBox = {
        width: 1500 * vm.scale,
        height: 250,
        scale: 2
      };

      //设置svg属性
      svg
        .attr("viewBox", function() {
          /**
           * https://segmentfault.com/a/1190000015661109
           * 第一个控制x轴的位置
           * 第二个控制y轴的位置
           * 第三个控制viewbox宽度
           * 第四个控制viewbox高度
           */
          return `500 100 ${viewBox.width} ${viewBox.width / viewBox.scale}`;
        })
        .attr("preserveAspectRatio", function() {
          return "xMidYMid meet";
        });

      //绘制线
      svg
        .selectAll("path")
        .data(lineData)
        .enter()
        .append("path")
        .on("click", (data, index, lines) => {
          this.$emit("lineClick", data, index, lines);
        })
        .attr("class", "d3-chart-path")
        .attr("d", function(d) {
          return d;
        })
        .attr("style", function(d) {
          return d.style || "";
        });

      //绘制小圆点
      const circle1R = 3;
      svg
        .selectAll("circle")
        .data(circleData)
        .enter()
        .append("circle")
        .on("click", (data, index, circles) => {
          this.$emit("circleClick", data, index, circles);
        })
        .attr("cx", function(d) {
          return d.x;
        })
        .attr("cy", function(d) {
          return d.y;
        })
        .attr("r", circle1R)
        .attr("class", "d3-chart-circle")
        .attr("style", function(d) {
          return d.style || "";
        });

      //必选选择一个元素，才能添加
      const circle2R = 8;
      svg
        .selectAll("__circle__")
        .data(circleLineData)
        .enter()
        .append("circle")
        .on("click", (data, index, circles) => {
          this.$emit("clCircleClick", data, index, circles);
        })
        .attr("cx", function(d) {
          return d.x;
        })
        .attr("cy", function(d) {
          return d.y;
        })
        .attr("r", circle2R)
        .attr("class", "d3-chart-cl-circle")
        .attr("style", function(d) {
          return d.circleStyle || "";
        });

      const atan = Math.atan.bind(Math);
      const sin = Math.sin.bind(Math);
      const cos = Math.cos.bind(Math);
      const abs = Math.abs.bind(Math);
      //绘制圆点之间的虚线
      svg
        .selectAll("__path__")
        .data(circleLineData)
        .enter()
        .append("path")
        .on("click", (data, index, lines) => {
          this.$emit("clLineClick", data, index, lines);
        })
        .attr("class", "d3-chart-cl-path")
        .attr("d", function(l) {
          const { x, y, toX, toY } = l;
          const xDistance = x - toX;
          const yDistance = y - toY;
          //弧度
          const A = atan(abs(yDistance / xDistance));
          const _x = circle2R * cos(A) * (xDistance > 0 ? -1 : 1);
          const _y = circle2R * sin(A) * (yDistance > 0 ? -1 : 1);

          const _x2 = circle1R * cos(A) * (xDistance > 0 ? 1 : -1);
          const _y2 = circle1R * sin(A) * (yDistance > 0 ? 1 : -1);

          return [`M${x + _x} ${y + _y} L${toX + _x2} ${toY + _y2}`];
        })
        .attr("style", function(d) {
          return d.lineStyle || "";
        });
    }
  },
  mounted() {}
};
</script>

<style lang="scss">
.d3-chart {
  svg {
    width: 100%;
    height: 100%;
  }
  .d3-chart-path {
    fill: none;
    stroke: rgb(194, 53, 49);
    stroke-width: 2px;
  }

  .d3-chart-circle,
  .d3-chart-path {
    cursor: pointer;
    stroke: rgb(194, 53, 49);
    fill: #fff;
  }
  .d3-chart-cl-circle {
    stroke-width: 3px;
    stroke: blue;
    fill: #ccc;
  }
  .d3-chart-cl-path {
    stroke-dasharray: 10, 10;
    fill: none;
    stroke: rgb(194, 53, 49);
    stroke-width: 2px;
  }
}
</style>
